package service;

import domain.Ant;
import domain.Pole;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import static java.lang.System.exit;
import static utils.Constants.gameState;

/**
 * 爬行游戏
 */
public class CreepingGame extends Frame {
    private Pole pole;//柱子
    private int poleLength;
    private List<Ant> antList; // 当前蚂蚁列表
    private int antCount;
    private int velocity;
    private int[] positions; //蚂蚁初始位置数组
    private static int state; // 游戏状态
    private static int round; // 游戏回合

    private int time; //计时器

    private int minTime=9999999;
    private int maxTime=-9999999;

    private final BufferedImage bufImg = new BufferedImage(750, 420, BufferedImage.TYPE_4BYTE_ABGR);

    /**
     * 构造函数，并调用初始化游戏窗口和游戏对象函数
     * @param poleLength
     * @param antCount
     * @param velocity
     * @param positions
     */
    public CreepingGame(int poleLength, int antCount,int velocity, int[] positions) {
        this.poleLength=poleLength;
        this.antCount = antCount;
        this.velocity = velocity;
        this.positions = positions;
        initFrame();
        initGame();
    }

    /**
     * 初始化游戏窗口
     */
    private void initFrame() {
        setSize(750, 420); // 设置窗口大小
        setTitle("AntClimbGame"); // 设置窗口标题
        setLocation(600, 300); // 窗口初始位置
        setBackground(new Color(124,234,142));

        //监听Jframe窗体关闭事件
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                exit(0);
            }
        });
        //窗口默认不可见，设置为可见
        setVisible(true);
    }

    /**
     * 初始化游戏中的各个对象
     */
    private void initGame() {
        time = 0;
        round = 0; //游戏回合
        pole = new Pole(poleLength);//初始化柱子
        antList = new ArrayList<>();

//        初始化蚂蚁并追加到数组
        for (int j = 0; j < antCount; j++)
        {
            Ant ant = new Ant(positions[j], j, velocity);
            antList.add(ant);
        }
//        游戏状态设置为就绪
        changeState(gameState.GAME_READY.ordinal());
//        启动用于刷新窗口的线程
        new Thread(() ->{
            while (true) {
                repaint(); // 通过调用repaint(),让JVM调用update()
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    //改变游戏状态
    private static void changeState(int gameState) {
        CreepingGame.state = gameState;
    }
    /**
     * 单独new一个thread，不断地调用repaint（），进而不断调用update（），对窗口不断进行重绘
     * @param g the specified Graphics window
     */
    @Override
    public void update(Graphics g) {
        g.setColor(Color.black);
        g.setFont(new Font("微软雅黑",Font.PLAIN,28));
        pole.drawPole(bufImg.getGraphics()); //绘制木棍

        if (state == gameState.GAME_READY.ordinal()) {
//            如果游戏是就绪状态，为蚂蚁赋予位置和方向，并将状态转为游戏开始
            time = 0;
            if (round < 32) {
                // 重置蚂蚁position
                for (int i = 0; i < antCount; i++) {
                    antList.get(i).setPosition(positions[i]);
                }
                //给蚂蚁赋初始方向 根据当前的round，计算出五位二进制数用于给蚂蚁赋方向
                for (int i = antList.size()-1; i >= 0; i--) {
                    int direction = round >>> i & 1;
                    antList.get(i).setDirection(direction);
                }
                changeState(gameState.GAME_START.ordinal());
            }
        } else if(state == gameState.GAME_START.ordinal()) {
//            如果游戏是开始状态，则让每一只蚂蚁爬行，绘制，检测碰撞
            for (Ant ant : antList) {
                ant.creep(pole);
                ant.drawAnt(bufImg.getGraphics());
            }

            testCollision();
            time++;
            //全部蚂蚁出界则该round回合游戏结束
            if (isAllReach()) {
                changeState(gameState.GAME_OVER.ordinal());
            }
        } else if(state == gameState.GAME_OVER.ordinal()){
//            如果游戏是结束状态，更新统计时间，并将游戏状态转为就绪
            if (time<minTime) {
                minTime=time;
            }
            if (time>maxTime) {
                maxTime=time;
            }
            System.out.println("第" + round + "局结束，用时：" + time);
            round++;
            changeState(gameState.GAME_READY.ordinal());
        }
//        先前的蚂蚁和柱子均绘制在这张bufImg上，先讲这张bufImg绘制到userPanel上
        g.drawImage(bufImg, 0, 0, null);
        g.drawString("最短时间：" + minTime,430,160);
        g.drawString( "最长时间： " + maxTime,430,210);
        g.drawString( "该回合当前耗时： " + time,430,260);
//        游戏结束
        if (round >= 32) {
            g.drawString("游戏结束",50,250);
        }
    }

    /**
     * 检测所有蚂蚁是否出界
     * @return
     */
    private boolean isAllReach()
    {
        for (int m = 0; m < antList.size(); m++)
        {
            if(antList.get(m).getPosition() > 100 && antList.get(m).getPosition() < 100 + poleLength)
            {
                return false;
            }
        }
        return true;
    }

    /**
     * 检测所有蚂蚁是否碰撞
     */
    private void testCollision()
    {
        for (int i = 0; i < antList.size(); i++)
        {
            if (!antList.get(i).isReach()) {
                for (int j = i + 1; j < antList.size(); j++) {
                    if (AntCollison(i, j)) {
                        antList.get(i).changeDirection();
                        antList.get(j).changeDirection();
                        break;
                    }
                }
            }
        }
    }

    /**
     * 检测两只蚂蚁是否碰撞
     * @param id1
     * @param id2
     * @return
     */
    private boolean AntCollison(int id1, int id2)
    {
        int left, right, distance;
//        两只蚂蚁各自的位置
        int posAnt1 = antList.get(id1).getPosition();
        int posAnt2 = antList.get(id2).getPosition();
        if (posAnt1 <= posAnt2) {
            left = id1;
            right = id2;
            distance = posAnt2 - posAnt1;
        }
        else {
            left = id2;
            right = id1;
            distance = posAnt1 - posAnt2;
        }
//        距离为0且方向相反
        if (distance == 0 && antList.get(left).getDirection() + antList.get(right).getDirection() == 1) {
            return true;
        } else if (distance <= velocity && (antList.get(left).getDirection()==1 && antList.get(right).getDirection() == 0))
        {
            return true;
        }

        return false;
    }
}

